在Sentry JS SDK的原始碼中,可以在packages/utils/src/instrument
的路徑下看到以下---
.
├── console.ts
├── fetch.ts
├── globalError.ts
├── globalUnhandledRejection.ts
├── handlers.ts
└── index.ts
是Sentry用來監控、覆蓋的模塊;同時,在handlers.ts
中就有定義:
export type InstrumentHandlerType =
| 'console'
| 'dom'
| 'fetch'
| 'fetch-body-resolved'
| 'history'
| 'xhr'
| 'error'
| 'unhandledrejection';
可以從上述得大概,Sentry列舉了它要捕獲和監控的各種類型,而有關錯誤的就是:
error
)--- 用於沒有被try-catch
而冒泡到全局的錯誤unhandledrejection
)---未處理的Promise reject事件,監控那些沒有被.catch()
處理的Promiseconsole.error
的內文、網路請求、dom錯誤資訊等等,則會透過覆蓋相關方法來獲取以下就來demo如何獲取全局錯誤和promise錯誤
在前端的上下文中,在沒有使用try-catch
來處理的異常錯誤,會拋到全局中、在瀏覽器console中出現紅字error。這時,我們可以利用覆蓋window.onerror
的函數來獲取:
window.onerror = function (message, source, lineno, colno, error) {
// maybe 上報 error
console.log('message, source, lineno, colno, error', message, source, lineno, colno, error);
}
其中的參數:
知道了這些,我們就在一個react 專案中嘗試看看:
demo.js
中定義一個SDK,在init
的時候把window.onerror
給覆蓋掉:class SelfSentry {
init() {
window.onerror = this._errorHandler;
}
_errorHandler(message, source, lineno, colno, error) {
console.log(
`Message:${message},\nSource:${source},\nLineon:${lineno},\nColno:${colno},\nError:${error}`,
);
}
}
export const selfSentry = new SelfSentry();
App.jsx
的最上層引入sdk,並執行selfSentry.init();
代表我們真的攔截到拋到全局的error,並且可以進一步處理。
當Promise被reject、但並沒有被處理的時候,會出發unhandledrejection
事件。這個可以利用覆蓋window. onunhandledrejection
來處理。
window.onunhandledrejection = function (event) {
// maybe 上報promise error
console.log(event)
};
那麼,我們就可以修改一下demo.js
,讓它也能捕獲到promise error:
class SelfSentry {
init() {
window.onerror = this._errorHandler;
window.onunhandledrejection = this._promiseErrorHandler;
}
_errorHandler(message, source, lineno, colno, error) {
console.log(
`Message:${message},\nSource:${source},\nLineon:${lineno},\nColno:${colno},\nError:${error}`,
);
}
_promiseErrorHandler(event) {
console.log(event);
}
}
export const selfSentry = new SelfSentry();
然後再App.jsx
中也mock一個promise error:
const throwPromiseError = async () => {
const mockPromise = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
reject('---promise error by myself');
}, 500);
});
await mockPromise();
};
觸發後,也可以在browser console中看到捕獲的promise error 內容:
今天我們大致了解Sentry捕獲前端error的類型,並且手寫了捕獲全局error和捕獲promise error,本文的程式碼都可以在Github repository中查看。
同時要注意到,監控sdk的初始化為什麼都建議在根目錄、根節點的最上面來引入和初始化,這是為了能夠在最一開始就覆蓋全局的error處理api。